using System;
using System.Collections;
using System.Xml;

namespace AleaClasses
{
	/// <summary>
	/// TNodes is a collection of TNode
	/// </summary>
	public class TNodes : CollectionBase, ITrackEdits
	{
		private TNodesTrackEdits fNodesTrackEdits;

		private void Constructor()
		{
			fNodesTrackEdits = new TNodesTrackEdits(this);
		}

		public TNodes(): base()
		{
			Constructor();
		}

		public TNodes(XmlElement aNodesElem, TLabels aLabels): base()
		{
			Constructor();

			// First pass: read all the nodes
			foreach(XmlElement lNodeElem in aNodesElem)
			{
				TNode lNode = new TNode(lNodeElem);
				this.Add(lNode);

				// got the existing node for this element
				XmlElement lArrivalLabelsElem = lNodeElem.SelectSingleNode("Labels") as XmlElement;
				if (lArrivalLabelsElem != null)
				{
					TLabels lCopiedArrivalLabels = new TLabels(lArrivalLabelsElem);
					TLabels lRealArrivalLabels = new TLabels();
					lRealArrivalLabels.ClearNeedsSave();
					
					foreach (TLabel lLabel in lCopiedArrivalLabels)
					{
						TLabel lRealLabel = aLabels.GetLabelByLabelCode(lLabel.LabelCode);
						if (lRealLabel != null)
							lRealArrivalLabels.Add(lRealLabel);
					}

					lNode.SetArrivalLabels(lRealArrivalLabels, false);
				}
			}

			// Second pass: read all the edges for the nodes
			foreach(XmlElement lNodeElem in aNodesElem)
			{
				TNode lReadInNode = new TNode(lNodeElem);
				if (lReadInNode != null)
				{
					TNode lExistingNode = this.GetNodeByNodeCode(lReadInNode.NodeCode);

					if (lExistingNode != null)
					{
						// got the existing node for this element
						XmlElement lEdgesElem = lNodeElem.SelectSingleNode("Edges") as XmlElement;
						if (lEdgesElem != null)
						{
							TEdges lEdges = new TEdges(lEdgesElem, this, aLabels);
							lExistingNode.SetEdges(lEdges, false);
						}
					}
				}
			}

		}

		public XmlElement SaveToXml(XmlDocument aDoc)
		{
			XmlElement retval = null;
			XmlElement elem = null;

			retval = aDoc.CreateElement("Nodes");

			foreach(TNode lNode in this)
			{
				elem = lNode.SaveToXml(aDoc);
				if (elem != null)
					retval.AppendChild(elem);
			}

			return retval;
		}

		public TNode this[ int index ]  
		{
			get  
			{
				return( (TNode) List[index] );
			}
			set  
			{
				if (List[index] != value)
				{
					List[index] = value;
					fNodesTrackEdits.DoSetNeedsSave();
				}	
			}
		}

		public int Add( TNode value )  
		{
			int retval = List.Add( value );
			fNodesTrackEdits.DoSetNeedsSave();
			return( retval );
		}

		public int IndexOf( TNode value )  
		{
			return( List.IndexOf( value ) );
		}

		public void Insert( int index, TNode value )  
		{
			List.Insert( index, value );
			fNodesTrackEdits.DoSetNeedsSave();
		}

		public void Remove( TNode value )  
		{
			List.Remove( value );
			fNodesTrackEdits.DoSetNeedsSave();
		}

		public bool Contains( TNode value )  
		{
			// If value is not of type TNode, this will return false.
			return( List.Contains( value ) );
		}

		protected override void OnInsert( int index, Object value )  
		{
			if ( value.GetType() != Type.GetType("AleaClasses.TNode") )
				throw new ArgumentException( "value must be of type TNode.", "value" );
		}

		protected override void OnRemove( int index, Object value )  
		{
			if ( value.GetType() != Type.GetType("AleaClasses.TNode") )
				throw new ArgumentException( "value must be of type TNode.", "value" );
		}

		protected override void OnSet( int index, Object oldValue, Object newValue )  
		{
			if ( newValue.GetType() != Type.GetType("AleaClasses.TNode") )
				throw new ArgumentException( "newValue must be of type TNode.", "newValue" );
		}

		protected override void OnValidate( Object value )  
		{
			if ( value.GetType() != Type.GetType("AleaClasses.TNode") )
				throw new ArgumentException( "value must be of type TNode." );
		}

		public TNode GetNodeByNodeCode(string aNodeCode)
		{
			TNode retval = null;

			foreach(TNode Node in this)
			{
				if (Node.NodeCode.ToUpper().Equals(aNodeCode.ToUpper()))
				{
					retval = Node;
				}
			}

			return retval;
		}

		#region ITrackEdits Members

		public bool NeedsSave()
		{
			return fNodesTrackEdits.NeedsSave();
		}

		public void ClearNeedsSave()
		{
			fNodesTrackEdits.ClearNeedsSave();
		}

		#endregion
	}

	public class TNodesTrackEdits: TTrackEdits
	{
		private TNodes fNodes;

		public TNodesTrackEdits(TNodes aNodes)
		{
			fNodes = aNodes;
		}

		protected override void ClearChildrenNeedsSave()
		{
			foreach (ITrackEdits te in fNodes)
			{
				te.ClearNeedsSave();
			}
		}

		protected override bool ChildrenNeedSave()
		{
			bool retval = false;

			foreach (ITrackEdits te in fNodes)
			{
				retval |= te.NeedsSave();
			}

			return retval;
		}
		
		internal void DoSetNeedsSave()
		{
			this.SetNeedsSave();
		}
	}
}
